﻿using UnityEngine;
using System.Collections.Generic;

/**********************************************************************
 * Available functions:
 *
 * 		virtual void Start()
 * 		virtual void Update()
 * 		void Push(Vector3 force)
 * 		void Brake()
 * 		void Scan(Vector3 direction, float angle, float distance)
 *		void Raycast(Vector3 direction)
 *		void Fire(Vector3 direction, float distance)
 * 		void SendMessage(string message)
 *		int getRobotId()
 *		void Print(string log)
 *		void SetName(string name)
 *		void SetTeam(string team)
 *
 *
 * Available variables:
 *
 *		Queue<ScanResult> scanResults
 *		Queue<RaycastResult> raycastResults
 *		Queue<KeyValuePair<int, string>> messages
 *		Queue<KeyValuePair<int, int>> receivedDamage
 *		Queue<KeyValuePair<int, int>> dealtDamage
 *	
 *		int life
 *		float fireCooldown
 *		Vector3 speed
 *		Vector3 position
 *		float deltaTime
 *
 *		bool autoCleanScan = true
 *		bool autoCleanRaycast = true
 *		bool autoCleanMessages = true
 *		bool autoCleanReceivedDamage = true
 *		bool autoCleanDealtDamage = true
 **********************************************************************/

public abstract class BaseRobot {

	protected abstract void Update();
	protected abstract void Start();
	
	public class RequestParams { public string request; }
	
	protected void Push(Vector3 force) {
		PushParams param = new PushParams();
		param.request = "Push";
		param.force = force;
		
		robotHandler.SendMessage("Request", param);
	}
	public class PushParams : RequestParams { public Vector3 force; }
	
	protected void Brake() {
		RequestParams param = new RequestParams();
		param.request = "Brake";
		
		robotHandler.SendMessage("Request", param);
	}
	
	protected void Scan(Vector3 direction, float angle, float distance) {
		ScanParams param = new ScanParams();
		param.request = "Scan";
		param.direction = direction; param.angle = angle; param.distance = distance;
		
		robotHandler.SendMessage("Request", param);
	}
	public class ScanParams : RequestParams { public Vector3 direction; public float angle; public float distance; }
	
	protected void Raycast(Vector3 direction) {
		RaycastParams param = new RaycastParams();
		param.request = "Raycast";
		param.direction = direction;
		
		robotHandler.SendMessage("Request", param);
	}
	public class RaycastParams : RequestParams { public Vector3 direction; }
	
	protected void Fire(Vector3 direction, float distance) {
		FireParams param = new FireParams();
		param.request = "Fire";
		param.direction = direction; param.distance = distance;
		
		robotHandler.SendMessage("Request", param);
	}
	public class FireParams : RequestParams { public Vector3 direction; public float distance; }
	
	protected void SendMessage(string message) {
		SendMessageParams param = new SendMessageParams();
		param.request = "Message";
		param.message = message;
		
		robotHandler.SendMessage("Request", param);
	}
	public class SendMessageParams : RequestParams { public string message; }
	
	public int GetRobotId() {
		return robotId;
	}
	
	protected void Print(string log) {
		Debug.Log("ROBOT_"+robotId+": "+log, robotHandler.gameObject);
	}
	
	protected void SetName(string name) {
		robotHandler.name = name;
	}
	
	protected void SetTeam(string team) {
		robotHandler.GetComponent<Robot>().SetTeam(team);
	}
	
	//--------------------------------------------------------------
	public void InternalStart(MonoBehaviour handler, int id) {
		robotHandler = handler;
		robotId = id;
		
//		contacts = new List<Contact>();
		scanResults = new Queue<ScanResult>();
		raycastResults = new Queue<RaycastResult>();
		messages = new Queue<KeyValuePair<int, string>>();
		receivedDamage = new Queue<KeyValuePair<int, int>>();
		dealtDamage = new Queue<KeyValuePair<int, int>>();
		
		Start();
	}
	
	public void InternalUpdate(float dt, RobotStatus status) {
		speed = status.speed;
		position = status.position;
		life = status.life;
		fireCooldown = status.fireCooldown;
		deltaTime = dt;
		
		Update();
		
		if (autoCleanDealtDamage) dealtDamage.Clear();
		if (autoCleanMessages) messages.Clear();
		if (autoCleanRaycast) raycastResults.Clear();
		if (autoCleanReceivedDamage) receivedDamage.Clear();
		if (autoCleanScan) scanResults.Clear();
	}
	
/*	public void OnContactEnter(Contact contact);
	public void OnContactExit(Contact contact);*/
	
	public void OnGetDamage(int amount, int enemyId) {
		receivedDamage.Enqueue(new KeyValuePair<int, int>(enemyId, amount));
	}
	
	public void OnDealDamage(int amount, int enemyId) {
		dealtDamage.Enqueue(new KeyValuePair<int, int>(enemyId, amount));
	}
	
	public void OnReceiveMessage(string message, int senderId) {
		messages.Enqueue(new KeyValuePair<int, string>(senderId, message));
	}
	
	public void OnScanHit(ScanResult result) {
		scanResults.Enqueue(result);
	}
	
	public void OnRayHit(RaycastResult result) {
		raycastResults.Enqueue(result);
	}

//	protected Queue<Contact> contacts;
	protected Queue<ScanResult> scanResults;
	protected Queue<RaycastResult> raycastResults;
	protected Queue<KeyValuePair<int, string>> messages;
	protected Queue<KeyValuePair<int, int>> receivedDamage;
	protected Queue<KeyValuePair<int, int>> dealtDamage;
	
	protected int life;
	protected float fireCooldown;
	protected Vector3 speed;
	protected Vector3 position;
	protected float deltaTime;
	
	protected bool autoCleanScan = true;
	protected bool autoCleanRaycast = true;
	protected bool autoCleanMessages = true;
	protected bool autoCleanReceivedDamage = true;
	protected bool autoCleanDealtDamage = true;
	
	private MonoBehaviour robotHandler;
	private int robotId;
	
	public class RobotStatus {
		public Vector3 speed;
		public Vector3 position;
		public int life;
		public float fireCooldown;
	}
	public class ScanResult {
		public int enemyId;
		public Vector3 position;
		public Vector3 direction;
		public float distance;
		public string team;
		public bool sameTeam;
	}
	public class RaycastResult {
		public GameObject gameObject;
		public Vector3 hitPosition;
	}
}
